#include <bits/stdc++.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>

using namespace std;

string testFile = "/data/test_data.txt";
string resultFile = "/projects/student/result.txt";

int node_num = 0;
uint nodes[2*280000];
int G[280000][50];
int RG[280000][50];
int len[280000];
int rlen[280000];

int ans3[500000][3], p3=0;
int ans4[500000][4], p4=0;
int ans5[1000000][5], p5=0;
int ans6[2000000][6], p6=0;
int ans7[3000000][7], p7=0;
char buf[77*3*1000000];
bool vis[280000];
int avl[280000];

inline unsigned int parse(char** s){
	char *p = *s;
	unsigned int val = *(p++) - '0';
	while(*p != ','){
		val = 10*val + *(p++) - '0';
	}
	*s = p+1;
	return val;
}
void loadData_and_createGrap(){
	int fd = open(testFile.c_str(), O_RDONLY);
    int file_size = lseek(fd, 0, SEEK_END);
    char* p_map =(char*)mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
    close(fd);
	char *p = p_map;
	uint inputs[2*280000], n=0;
	while(*p != '\0'){
		inputs[n++]=(parse(&p));
		inputs[n++]=(parse(&p));
		while(*p != '\n') p++;
		p++;
	}
	memcpy(nodes,inputs,4*2*280000);
	sort(nodes,nodes+2*280000);
	node_num = unique(nodes,nodes+2*280000) - nodes;
	unordered_map<uint, int> idHash;
	for(int i=0; i<node_num; i++){idHash[nodes[i]] = i;len[i]=0;rlen[i]=0;}
	for(int i=0,a=0,b=0; i<n; i+=2){
		a=idHash[inputs[i]];
		b=idHash[inputs[i+1]];
		G[a][len[a]++]=b;
		RG[b][rlen[b]++]=a;
	}
	for(int i=0; i<node_num; i++) sort(G[i],G[i]+len[i]);
	munmap(p_map, file_size);
}

void save(){
	int data_size = sprintf(buf,"%d\n",p3+p4+p5+p6+p7);
	int i=0;
	for(i=0; i<p3; i++) data_size += sprintf(buf+data_size,"%u,%u,%u\n",nodes[ans3[i][0]],nodes[ans3[i][1]],nodes[ans3[i][2]]);
	for(i=0; i<p4; i++) data_size += sprintf(buf+data_size,"%u,%u,%u,%u\n",nodes[ans4[i][0]],nodes[ans4[i][1]],nodes[ans4[i][2]],nodes[ans4[i][3]]);
	for(i=0; i<p5; i++) data_size += sprintf(buf+data_size,"%u,%u,%u,%u,%u\n",nodes[ans5[i][0]],nodes[ans5[i][1]],nodes[ans5[i][2]],nodes[ans5[i][3]],nodes[ans5[i][4]]);
	for(i=0; i<p6; i++) data_size += sprintf(buf+data_size,"%u,%u,%u,%u,%u,%u\n",nodes[ans6[i][0]],nodes[ans6[i][1]],nodes[ans6[i][2]],nodes[ans6[i][3]],nodes[ans6[i][4]],nodes[ans6[i][5]]);
	for(i=0; i<p7; i++) data_size += sprintf(buf+data_size,"%u,%u,%u,%u,%u,%u,%u\n",nodes[ans7[i][0]],nodes[ans7[i][1]],nodes[ans7[i][2]],nodes[ans7[i][3]],nodes[ans7[i][4]],nodes[ans7[i][5]],nodes[ans7[i][6]]);
	int fd = open(resultFile.c_str(), O_RDWR|O_CREAT, 0666);
	write(fd, buf, data_size);
	close(fd);
}

int path[7];
void dfs(int head, int cur, int dep){
	path[dep-1]=cur;
	for(int i=0,v=G[cur][0]; i<len[cur]; v=G[cur][++i]){
		if(v==head){
			if(dep>2 && dep<8){
				switch(dep){
					case 3:
						memcpy(ans3[p3++], path, 12);
						break;
					case 4:
						memcpy(ans4[p4++], path, 16);
						break;
					case 5:
						memcpy(ans5[p5++], path, 20);
						break;
					case 6:
						memcpy(ans6[p6++], path, 24);
						break;
					case 7:
						memcpy(ans7[p7++], path, 28);
						break;
				}
			}
			continue;
		}
		if(vis[v]==true || avl[v]!=head) continue;
		if(dep==7) continue;
		vis[cur] = true;
		dfs(head, v, dep+1);
		vis[cur] = false;
	}
}
void dfs1(int head, int cur, int dep){
	for(int i=0,v=G[cur][0]; i<len[cur]; v=G[cur][++i]){
		if(v < head || vis[v]==true) continue;
		avl[v] = head;
		if(dep == 3) continue;
		vis[cur] = true;
		dfs1(head, v, dep+1);
		vis[cur] = false;
	}
}
void dfs2(int head, int cur, int dep){
	for(int i=0,v=RG[cur][0]; i<rlen[cur]; v=RG[cur][++i]){
		if(v < head || vis[v]==true) continue;
		avl[v] = head;
		if(dep == 3) continue;
		vis[cur] = true;
		dfs2(head, v, dep+1);
		vis[cur] = false;
	}
}
void solve1(){
	memset(vis, 0, sizeof(vis));
	memset(avl, -1, sizeof(avl));
	for(int i=0;i<node_num;i++){
		if(len[i]!=0){
			dfs1(i,i,1);
			dfs2(i,i,1);
			dfs(i,i,1);
		}
	}
}

void solve2(){
	vector<int> uSet2, uSet3, uSet4;
	int p[7];
	vector<unordered_map<int,vector<int>>> P1(node_num);
	unordered_map<int,vector<int>>::iterator iter;
	for(int u=0; u<node_num; u++){
		for(int i=0,v1=G[u][0]; i<len[u]; v1=G[u][++i]){
			for(int j=0,v2=G[v1][0]; j<len[v1]; v2=G[v1][++j]){
				if(v2>v1 || v2==u) continue;
				P1[u][v2].push_back(v1);
			}
		}
	}
	vector<unordered_map<int,vector<vector<int>>>> P2(node_num);
	vector<int> tmp = vector<int>(2);
	for(int u=0; u<node_num; u++){
		for(int i=0,v1=G[u][0]; i<len[u]; v1=G[u][++i]){
			for(int j=0,v2=G[v1][0]; j<len[v1]; v2=G[v1][++j]){
				if(v2 != u){
					for(int k=0,v3=G[v2][0]; k<len[v2]; v3=G[v2][++k]){
						if(v1<v3 || v2<v3 || v1==v3 || v3==u) continue;
						tmp[0]=v1;
						tmp[1]=v2;
						P2[u][v3].push_back(tmp);
					}
				}
				else continue;
			}
		}
	}
	for(int u=0; u<node_num; u++){
		p[0]=u;
		for(int i=0,v1=G[u][0]; i<len[u]; v1=G[u][++i]){
			if(v1 < u) continue;
			p[1]=v1;
			for(int j=0,v2=G[v1][0]; j<len[v1]; v2=G[v1][++j]) if(v2 > u) uSet2.push_back(v2);
			for(int& v2:uSet2){
				p[2]=v2;
				if(find(G[v2],G[v2]+len[v2],u)!=G[v2]+len[v2]){
					memcpy(ans3+p3++,p,12);
				}
				for(int k=0,v3=G[v2][0]; k<len[v2]; v3=G[v2][++k]) if(v3 > u && v3!=v1) uSet3.push_back(v3);
				for(int& v3:uSet3){
					p[3]=v3;
					if(find(G[v3],G[v3]+len[v3],u)!=G[v3]+len[v3]){
						memcpy(ans4+p4++,p,16);
					}
					for(int m=0,v4=G[v3][0]; m<len[v3]; v4=G[v3][++m]) if(v4 > u && v4!=v2 && v4!=v1) uSet4.push_back(v4);
					for(int& v4:uSet4){
						p[4]=v4;
						if(find(G[v4],G[v4]+len[v4],u)!=G[v4]+len[v4]){
							memcpy(ans5+p5++,p,20);
						}
					}
					uSet4.clear();
				}
				uSet3.clear();
			}
			uSet2.clear();
		}
	}
	for(int u=0; u<node_num; u++){
		p[0]=u;
		for(int i=0,v1=G[u][0]; i<len[u]; v1=G[u][++i]){
			if(v1 < u) continue;
			p[1]=v1;
			for(int j=0,v2=G[v1][0]; j<len[v1]; v2=G[v1][++j]){
				if(v2 <= u) continue;
				p[2]=v2;
				for(int k=0,v3=G[v2][0]; k<len[v2]; v3=G[v2][++k]){
					if(v3 <= u || v3==v1) continue;
					p[3]=v3;
					for(int m=0,v4=G[v3][0]; m<len[v3]; v4=G[v3][++m]){
						if(v4 <= u || v4==v2 || v4==v1) continue;
						p[4]=v4;
						if((iter = P1[v4].find(u))!=P1[v4].end()){
							for(int& v5:iter->second){
								p[5] = v5;
								if(v5!=v3 && v5!=v2 && v5!=v1){
									memcpy(ans6+p6++,p,24);
								}
							}
						}
					}
				}
			}
		}
	}
	int v5,v6;
	unordered_map<int,vector<vector<int>>>::iterator iter1;
	for(int u=0; u<node_num; u++){
		p[0]=u;
		for(int i=0,v1=G[u][0]; i<len[u]; v1=G[u][++i]){
			if(v1 < u) continue;
			p[1]=v1;
			for(int j=0,v2=G[v1][0]; j<len[v1]; v2=G[v1][++j]){
				if(v2 <= u) continue;
				p[2]=v2;
				for(int k=0,v3=G[v2][0]; k<len[v2]; v3=G[v2][++k]){
					if(v3 <= u || v3==v1) continue;
					p[3]=v3;
					for(int m=0,v4=G[v3][0]; m<len[v3]; v4=G[v3][++m]){
						if(v4 <= u || v4==v2 || v4==v1) continue;
						p[4]=v4;
						if((iter1 = P2[v4].find(u))!=P2[v4].end()){
							for(auto& each:iter1->second){
								v5=each[0];
								v6=each[1];
								if(v5!=v3 && v5!=v2 && v5!=v1 && v6!=v3 && v6!=v2 && v6!=v1){
									p[5] = v5;
									p[6] = v6;
									memcpy(ans7+p7++,p,28);
								}
							}
						}
					}
				}
			}
		}
	}
}

int main(int argc, char* argv[]){
	loadData_and_createGrap();
	if(280000/node_num > 10){
		solve2();
	}else{
		solve1();
	}
	save();
	return 0;
}